﻿using System;
using System.Collections.Generic;
using System.Drawing;
using ProjectN.Core.Element;
using ProjectN.Core.Instance;

namespace ProjectN.Core.Fore
{
    static partial class Utilities
    {
        public static Color asColor(int id)
        {
            return Color.FromArgb(
                255,
                id >> 16 & 0xff,
                id >> 8 & 0xff,
                id >> 0 & 0xff
            );
        }
        public static int asId(Color color)
        {
            if (color.ToArgb() == -1)
                return -1;
            return
                0x00ff0000 & color.R << 16 |
                0x0000ff00 & color.G << 8 |
                0x000000ff & color.B << 0;
        }
    }

    public class PageElementSelector : IDisposable
    {
        public PageElementSelector(IPage page, Action<string>? onChangeStatus = null)
        {
            changeStatus = onChangeStatus ?? new Action<string>(status => { });
            Page = page;
        }

        // 这些都会在调用 Page.set 时设置，实际上构造函数运行后就不再是 null
        private IPage page = null!;
        private Bitmap map = null!;
        private Graphics gr = null!;
        private string status = null!;

        private Action<string> changeStatus;

        public IPage Page
        {
            get => page;
            set
            {
                page = value;

                map?.Dispose();
                gr?.Dispose();

                map = new Bitmap(PWidth, PHeight);
                gr = Graphics.FromImage(map);
                gr.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;

                Update();
            }
        }

        public void Update()
        {
            Status = Properties.Resources.S_DRAWING;
            gr.Clear(Utilities.asColor(-1));

            Queue<IElement> draw_queue = new Queue<IElement>();

            foreach (var pair in page.IdentifiedElements)
            {
                pair.ReadValues(out int elementId, out IElement element);
                if (pair.Value == null || element.Type.HasFlag(ElementType.Completion))
                    break;
                draw_queue.Enqueue(element);
                while (draw_queue.Count > 0)
                {
                    IElement current = draw_queue.Dequeue();
                    if (current == null)
                        continue;
                    if (current.Type.HasFlag(ElementType.Basic))
                        current.OnDraw(gr, Utilities.asColor(elementId));
                    if (current.Type.HasFlag(ElementType.Advanced))
                        foreach (IElement sub in current.Subelements)
                            draw_queue.Enqueue(sub);
                }
            }
            Status = Properties.Resources.S_READY;
        }
        /// <param name="position">表示点击位置的 <see cref="Point"/> 对象</param>
        /// <returns>
        /// <see cref="-1"/>表示没有元素被点击 否则为被点击的元素 id
        /// </returns>
        public int ClickedElementId(Point position)
        {
            if (position.X >= PWidth || position.Y >= PHeight)
                return -1;
            else
                return Utilities.asId(map.GetPixel(position.X, position.Y));
        }

        public string Status
        {
            get { return status; }
            set
            {
                status = value;
                changeStatus(value);
            }
        }
        public int PWidth { get { return page.Width; } }
        public int PHeight { get { return page.Height; } }

        #region IDisposable Support
        private bool disposedValue = false; // 要检测冗余调用

        void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    gr.Dispose();
                    map.Dispose();
                }

                // TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。
                // TODO: 将大型字段设置为 null。

                disposedValue = true;
            }
        }

        ~PageElementSelector()
        {
            // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
            Dispose(false);
        }

        // 添加此代码以正确实现可处置模式。
        public void Dispose()
        {
            // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        #endregion
    }
}
